﻿using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

using Newtonsoft.Json;

using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;


namespace Utils.WeChat
{
    class Cryptography
    {

        /// <summary>
        /// 微信支付投
        /// </summary>
        /// <param name="privateKey"></param>
        /// <param name="merchantId"></param>
        /// <param name="serialNo"></param>
        /// <param name="method"></param>
        /// <param name="uri"></param>
        /// <param name="body"></param>
        /// <returns></returns>
        public static string BuildAuth(string privateKey, string merchantId, string serialNo, string method, string uri, string body)
        {
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            string nonce = Guid.NewGuid().ToString("N");
            string message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
            string signature = RSASign(privateKey, message);
            Console.WriteLine(message);
            Console.WriteLine(signature);
            return $"WECHATPAY2-SHA256-RSA2048 mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
        }

        /// <summary>
        /// RSA 签名
        /// </summary>
        /// <param name="privateKey"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public static string RSASign(string privateKey, string message)
        {
            byte[] keyData = Convert.FromBase64String(privateKey);
            var rsaProvider = new RSACryptoServiceProvider();
            rsaProvider.ImportPkcs8PrivateKey(keyData, out int len);
            byte[] data = Encoding.UTF8.GetBytes(message);
            return Convert.ToBase64String(rsaProvider.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
        }



        public static string AesGcmDecrypt(string aesKey, string associatedData, string nonce, string ciphertext)
        {
            GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
            AeadParameters aeadParameters = new AeadParameters(
                new KeyParameter(Encoding.UTF8.GetBytes(aesKey)),
                128,
                Encoding.UTF8.GetBytes(nonce),
                Encoding.UTF8.GetBytes(associatedData));
            gcmBlockCipher.Init(false, aeadParameters);

            byte[] data = Convert.FromBase64String(ciphertext);
            byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
            int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
            gcmBlockCipher.DoFinal(plaintext, length);
            return Encoding.UTF8.GetString(plaintext);
        }

        /// <summary>
        /// AES 解密
        /// </summary>
        /// <param name="text"></param>
        /// <param name="AesKey"></param>
        /// <param name="AesIV"></param>
        /// <returns></returns>
        public static string AESDecrypt(string text, string AesKey, string AesIV)
        {
            try
            {
                byte[] encryptedData = Convert.FromBase64String(text);  // strToToHexByte(text);
                RijndaelManaged rijndaelCipher = new RijndaelManaged();
                rijndaelCipher.Mode = CipherMode.CBC;
                rijndaelCipher.Padding = PaddingMode.PKCS7;
                using (ICryptoTransform transform = rijndaelCipher.CreateDecryptor(Convert.FromBase64String(AesKey), Convert.FromBase64String(AesIV)))
                {
                    byte[] plainText = transform.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
                    string result = Encoding.UTF8.GetString(plainText);
                    return result;
                }
            }
            catch (Exception)
            {
                throw new Exception("iv已失效");
            }
        }
    }
}
